{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6fb92deb-d89e-439b-855d-c7f2607d794b",
   "metadata": {},
   "source": [
    "# How to use the async API for Agents\n",
    "\n",
    "LangChain provides async support for Agents by leveraging the [asyncio](https://docs.python.org/3/library/asyncio.html) library.\n",
    "\n",
    "Async methods are currently supported for the following `Tools`: [`SerpAPIWrapper`](https://github.com/hwchase17/langchain/blob/master/langchain/serpapi.py) and [`LLMMathChain`](https://github.com/hwchase17/langchain/blob/master/langchain/chains/llm_math/base.py). Async support for other agent tools are on the roadmap.\n",
    "\n",
    "For `Tool`s that have a `coroutine` implemented (the two mentioned above), the `AgentExecutor` will `await` them directly. Otherwise, the `AgentExecutor` will call the `Tool`'s `func` via `asyncio.get_event_loop().run_in_executor` to avoid blocking the main runloop.\n",
    "\n",
    "You can use `arun` to call an `AgentExecutor` asynchronously."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97800378-cc34-4283-9bd0-43f336bc914c",
   "metadata": {},
   "source": [
    "## Serial vs. Concurrent Execution\n",
    "\n",
    "In this example, we kick off agents to answer some questions serially vs. concurrently. You can see that concurrent execution significantly speeds this up."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "da5df06c-af6f-4572-b9f5-0ab971c16487",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import asyncio\n",
    "import time\n",
    "\n",
    "from langchain.agents import initialize_agent, load_tools\n",
    "from langchain.agents import AgentType\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.callbacks.stdout import StdOutCallbackHandler\n",
    "from langchain.callbacks.base import CallbackManager\n",
    "from langchain.callbacks.tracers import LangChainTracer\n",
    "from aiohttp import ClientSession\n",
    "\n",
    "questions = [\n",
    "    \"Who won the US Open men's final in 2019? What is his age raised to the 0.334 power?\",\n",
    "    \"Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?\",\n",
    "    \"Who won the most recent formula 1 grand prix? What is their age raised to the 0.23 power?\",\n",
    "    \"Who won the US Open women's final in 2019? What is her age raised to the 0.34 power?\",\n",
    "    \"Who is Beyonce's husband? What is his age raised to the 0.19 power?\"\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "fd4c294e-b1d6-44b8-b32e-2765c017e503",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to find out who won the US Open men's final in 2019 and then calculate his age raised to the 0.334 power.\n",
      "Action: Search\n",
      "Action Input: \"US Open men's final 2019 winner\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mRafael Nadal\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Rafael Nadal's age\n",
      "Action: Search\n",
      "Action Input: \"Rafael Nadal age\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m36 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 36 raised to the 0.334 power\n",
      "Action: Calculator\n",
      "Action Input: 36^0.334\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 3.3098250249682484\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Rafael Nadal, aged 36, won the US Open men's final in 2019 and his age raised to the 0.334 power is 3.3098250249682484.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n",
      "Action: Search\n",
      "Action Input: \"Olivia Wilde boyfriend\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mJason Sudeikis\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' age\n",
      "Action: Search\n",
      "Action Input: \"Jason Sudeikis age\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m47 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 47 raised to the 0.23 power\n",
      "Action: Calculator\n",
      "Action Input: 47^0.23\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.4242784855673896\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Jason Sudeikis, Olivia Wilde's boyfriend, is 47 years old and his age raised to the 0.23 power is 2.4242784855673896.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to find out who won the grand prix and then calculate their age raised to the 0.23 power.\n",
      "Action: Search\n",
      "Action Input: \"Formula 1 Grand Prix Winner\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mMax Verstappen\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Max Verstappen's age\n",
      "Action: Search\n",
      "Action Input: \"Max Verstappen Age\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m25 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 25 raised to the 0.23 power\n",
      "Action: Calculator\n",
      "Action Input: 25^0.23\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 1.84599359907945\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Max Verstappen, 25 years old, raised to the 0.23 power is 1.84599359907945.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to find out who won the US Open women's final in 2019 and then calculate her age raised to the 0.34 power.\n",
      "Action: Search\n",
      "Action Input: \"US Open women's final 2019 winner\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mBianca Andreescu defeated Serena Williams in the final, 6–3, 7–5 to win the women's singles tennis title at the 2019 US Open. It was her first major title, and she became the first Canadian, as well as the first player born in the 2000s, to win a major singles title.\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Bianca Andreescu's age.\n",
      "Action: Search\n",
      "Action Input: \"Bianca Andreescu age\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m22 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the age of Bianca Andreescu and can calculate her age raised to the 0.34 power.\n",
      "Action: Calculator\n",
      "Action Input: 22^0.34\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.8603798598506933\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
      "Final Answer: Bianca Andreescu won the US Open women's final in 2019 and her age raised to the 0.34 power is 2.8603798598506933.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to find out who Beyonce's husband is and then calculate his age raised to the 0.19 power.\n",
      "Action: Search\n",
      "Action Input: \"Who is Beyonce's husband?\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mJay-Z\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Jay-Z's age\n",
      "Action: Search\n",
      "Action Input: \"How old is Jay-Z?\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m53 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 53 raised to the 0.19 power\n",
      "Action: Calculator\n",
      "Action Input: 53^0.19\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.12624064206896\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Jay-Z is Beyonce's husband and his age raised to the 0.19 power is 2.12624064206896.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "Serial executed in 65.11 seconds.\n"
     ]
    }
   ],
   "source": [
    "def generate_serially():\n",
    "    for q in questions:\n",
    "        llm = OpenAI(temperature=0)\n",
    "        tools = load_tools([\"llm-math\", \"serpapi\"], llm=llm)\n",
    "        agent = initialize_agent(\n",
    "            tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION verbose=True\n",
    "        )\n",
    "        agent.run(q)\n",
    "\n",
    "s = time.perf_counter()\n",
    "generate_serially()\n",
    "elapsed = time.perf_counter() - s\n",
    "print(f\"Serial executed in {elapsed:0.2f} seconds.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "076d7b85-45ec-465d-8b31-c2ad119c3438",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n",
      "Action: Search\n",
      "Action Input: \"Olivia Wilde boyfriend\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out who Beyonce's husband is and then calculate his age raised to the 0.19 power.\n",
      "Action: Search\n",
      "Action Input: \"Who is Beyonce's husband?\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mJay-Z\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out who won the grand prix and then calculate their age raised to the 0.23 power.\n",
      "Action: Search\n",
      "Action Input: \"Formula 1 Grand Prix Winner\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out who won the US Open women's final in 2019 and then calculate her age raised to the 0.34 power.\n",
      "Action: Search\n",
      "Action Input: \"US Open women's final 2019 winner\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mJason Sudeikis\u001b[0m\n",
      "Thought:\n",
      "Observation: \u001b[33;1m\u001b[1;3mMax Verstappen\u001b[0m\n",
      "Thought:\n",
      "Observation: \u001b[33;1m\u001b[1;3mBianca Andreescu defeated Serena Williams in the final, 6–3, 7–5 to win the women's singles tennis title at the 2019 US Open. It was her first major title, and she became the first Canadian, as well as the first player born in the 2000s, to win a major singles title.\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' age\n",
      "Action: Search\n",
      "Action Input: \"Jason Sudeikis age\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out Jay-Z's age\n",
      "Action: Search\n",
      "Action Input: \"How old is Jay-Z?\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m53 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out who won the US Open men's final in 2019 and then calculate his age raised to the 0.334 power.\n",
      "Action: Search\n",
      "Action Input: \"US Open men's final 2019 winner\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mRafael Nadal defeated Daniil Medvedev in the final, 7–5, 6–3, 5–7, 4–6, 6–4 to win the men's singles tennis title at the 2019 US Open. It was his fourth US ...\u001b[0m\n",
      "Thought:\n",
      "Observation: \u001b[33;1m\u001b[1;3m47 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Max Verstappen's age\n",
      "Action: Search\n",
      "Action Input: \"Max Verstappen Age\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m25 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Bianca Andreescu's age.\n",
      "Action: Search\n",
      "Action Input: \"Bianca Andreescu age\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m22 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 53 raised to the 0.19 power\n",
      "Action: Calculator\n",
      "Action Input: 53^0.19\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out the age of the winner\n",
      "Action: Search\n",
      "Action Input: \"Rafael Nadal age\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to calculate 47 raised to the 0.23 power\n",
      "Action: Calculator\n",
      "Action Input: 47^0.23\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m36 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 25 raised to the 0.23 power\n",
      "Action: Calculator\n",
      "Action Input: 25^0.23\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.12624064206896\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the age of Bianca Andreescu and can calculate her age raised to the 0.34 power.\n",
      "Action: Calculator\n",
      "Action Input: 22^0.34\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 1.84599359907945\u001b[0m\n",
      "Thought:\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.4242784855673896\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now need to calculate his age raised to the 0.334 power\n",
      "Action: Calculator\n",
      "Action Input: 36^0.334\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.8603798598506933\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Jay-Z is Beyonce's husband and his age raised to the 0.19 power is 2.12624064206896.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Max Verstappen, 25 years old, raised to the 0.23 power is 1.84599359907945.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 3.3098250249682484\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Jason Sudeikis, Olivia Wilde's boyfriend, is 47 years old and his age raised to the 0.23 power is 2.4242784855673896.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
      "Final Answer: Bianca Andreescu won the US Open women's final in 2019 and her age raised to the 0.34 power is 2.8603798598506933.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Rafael Nadal, aged 36, won the US Open men's final in 2019 and his age raised to the 0.334 power is 3.3098250249682484.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "Concurrent executed in 12.38 seconds.\n"
     ]
    }
   ],
   "source": [
    "async def generate_concurrently():\n",
    "    agents = []\n",
    "    # To make async requests in Tools more efficient, you can pass in your own aiohttp.ClientSession, \n",
    "    # but you must manually close the client session at the end of your program/event loop\n",
    "    aiosession = ClientSession()\n",
    "    for _ in questions:\n",
    "        manager = CallbackManager([StdOutCallbackHandler()])\n",
    "        llm = OpenAI(temperature=0, callback_manager=manager)\n",
    "        async_tools = load_tools([\"llm-math\", \"serpapi\"], llm=llm, aiosession=aiosession, callback_manager=manager)\n",
    "        agents.append(\n",
    "            initialize_agent(async_tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True, callback_manager=manager)\n",
    "        )\n",
    "    tasks = [async_agent.arun(q) for async_agent, q in zip(agents, questions)]\n",
    "    await asyncio.gather(*tasks)\n",
    "    await aiosession.close()\n",
    "\n",
    "s = time.perf_counter()\n",
    "# If running this outside of Jupyter, use asyncio.run(generate_concurrently())\n",
    "await generate_concurrently()\n",
    "elapsed = time.perf_counter() - s\n",
    "print(f\"Concurrent executed in {elapsed:0.2f} seconds.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97ef285c-4a43-4a4e-9698-cd52a1bc56c9",
   "metadata": {},
   "source": [
    "## Using Tracing with Asynchronous Agents\n",
    "\n",
    "To use tracing with async agents, you must pass in a custom `CallbackManager` with `LangChainTracer` to each agent running asynchronously. This way, you avoid collisions while the trace is being collected."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "44bda05a-d33e-4e91-9a71-a0f3f96aae95",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to find out who won the US Open men's final in 2019 and then calculate his age raised to the 0.334 power.\n",
      "Action: Search\n",
      "Action Input: \"US Open men's final 2019 winner\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3mRafael Nadal\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to find out Rafael Nadal's age\n",
      "Action: Search\n",
      "Action Input: \"Rafael Nadal age\"\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m36 years\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 36 raised to the 0.334 power\n",
      "Action: Calculator\n",
      "Action Input: 36^0.334\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 3.3098250249682484\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: Rafael Nadal, aged 36, won the US Open men's final in 2019 and his age raised to the 0.334 power is 3.3098250249682484.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "# To make async requests in Tools more efficient, you can pass in your own aiohttp.ClientSession, \n",
    "# but you must manually close the client session at the end of your program/event loop\n",
    "aiosession = ClientSession()\n",
    "tracer = LangChainTracer()\n",
    "tracer.load_default_session()\n",
    "manager = CallbackManager([StdOutCallbackHandler(), tracer])\n",
    "\n",
    "# Pass the manager into the llm if you want llm calls traced.\n",
    "llm = OpenAI(temperature=0, callback_manager=manager)\n",
    "\n",
    "async_tools = load_tools([\"llm-math\", \"serpapi\"], llm=llm, aiosession=aiosession)\n",
    "async_agent = initialize_agent(async_tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True, callback_manager=manager)\n",
    "await async_agent.arun(questions[0])\n",
    "await aiosession.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
